package org.javia.arity;

import static org.junit.Assert.*;


import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;

import static org.mockito.Mockito.*;

public class LexerTest {

	Lexer lexer;
	TokenConsumer consumer;
	@Before
	public void setUp() throws Exception {

		lexer= new Lexer(new SyntaxException().set("mock",1));
		consumer= mock(TokenConsumer.class); 
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testLexer() {
		//fail("Not yet implemented");
	}

	@Test(expected=SyntaxException.class)
	public void testException1() throws SyntaxException{
		lexer.scan("$", consumer); //send invalid input
	}
	
	@Test(expected=SyntaxException.class)
	public void testInvalid() throws SyntaxException{
		lexer.scan("áđ", consumer);
		
	}
	
	@Test
	public void testExp() throws SyntaxException{
		lexer.scan("(1.004E-10)-4",consumer);
		verify(consumer,times(2)).push(Lexer.TOK_NUMBER);
		
	}
	
	@Test
	public void testScan() throws SyntaxException {
		
		
			lexer.scan("  2+2*2+1/2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2+2", consumer);
			verify(consumer, times(34)).push(Lexer.TOK_NUMBER);
			verify(consumer, times(31)).push(Lexer.TOK_ADD);
			verify(consumer, times(1)).push(Lexer.TOK_MUL);
			verify(consumer, times(1)).push(Lexer.TOK_DIV);
			
		
			consumer= mock(TokenConsumer.class);
		
			lexer.scan("(2!)-(3%1)", consumer);
			verify(consumer,times(3)).push(Lexer.TOK_NUMBER);
			verify(consumer).push(Lexer.TOK_FACT);
			verify(consumer,times(2)).push(Lexer.TOK_LPAREN);
			verify(consumer,times(2)).push(Lexer.TOK_RPAREN);
			verify(consumer).push(Lexer.TOK_SUB);
			verify(consumer).push(Lexer.TOK_PERCENT);

		
	    	consumer= mock(TokenConsumer.class);

			lexer.scan("0x10+0xA", consumer);
			lexer.scan("0b1001+0b1111", consumer);
			lexer.scan("0o10*0o2", consumer);
			lexer.scan(".000*00.0", consumer);
			lexer.scan("0xF*0xf", consumer);
			verify(consumer,times(10)).push(Lexer.TOK_NUMBER); //2 times 5 cases
			verify(consumer,times(2)).push(Lexer.TOK_ADD);
			verify(consumer,times(3)).push(Lexer.TOK_MUL);

		
		
	}
	
	@Test
	public void testCalls() throws SyntaxException{
		lexer.scan(".",consumer); //is 0
		lexer.scan("  sin'  (  0  )  ",consumer);//to test spaces
		lexer.scan("sin'(0)",consumer);
		lexer.scan("SIN0",consumer);
		lexer.scan("2^1",consumer);
		verify(consumer,times(5)).push(Lexer.TOK_NUMBER);
		verify(consumer,times(1)).push(Lexer.TOK_CONST);
		verify(consumer,times(2)).push(argThat (new TokenCallMatcher())) ;
	}
	
	
	char UNICODE_MINUS = '\u2212',
    UNICODE_MUL   = '\u00d7',
    UNICODE_DIV   = '\u00f7',
    UNICODE_SQRT  = '\u221a';
	
	@Test
	public void testUnicode() throws SyntaxException{
		 lexer.scan("2"+UNICODE_DIV+"2", consumer);
		 lexer.scan("2"+UNICODE_MUL+"2", consumer);
		 lexer.scan("2"+UNICODE_MINUS+"2", consumer);
		 lexer.scan(UNICODE_SQRT+"2", consumer);
		 lexer.scan("2*\u0391*\u03b2",consumer);
		 verify(consumer,times(8)).push(Lexer.TOK_NUMBER);
		 verify(consumer).push(Lexer.TOK_DIV);
		 verify(consumer,times(2)).push(Lexer.TOK_CONST); 
//		 verify(consumer).push(Lexer.TOK_MUL);
		 verify(consumer).push(Lexer.TOK_SUB);
		 verify(consumer).push(Lexer.TOK_SQRT);
		 

		
	}

	

	
}


class TokenCallMatcher extends ArgumentMatcher<Token> {
			@Override
	         public boolean matches(Object ob) {
	        	 Token o= (Token)ob;
	            return (o.id==Lexer.CALL && o.assoc==Token.PREFIX);
	         }

		
	     }
